package com.xyebank.cn.aop;

import com.alibaba.dcm.DnsCacheManipulator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.*;

@Aspect
@Component
@PropertySource("classpath:ipProperties/ip.properties")
@Slf4j
public class RestAop {

    /**
     * 设置切入点未restTemplete下的所有方法
     */
    @Pointcut("execution(public * org.springframework.web.client.RestTemplate.*(..))")
    public void aopRestTemplete() {
    }

    @Autowired
    private Environment env;


    /**
     * 前置通知
     *
     * @param joinPoint
     * @throws Throwable
     */
    @Before("aopRestTemplete()")
    public void deBefore(JoinPoint joinPoint) throws Throwable {
        /*ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 记录下请求内容
        System.out.println("URL : " + request.getRequestURL().toString());
        System.out.println("HTTP_METHOD : " + request.getMethod());
        System.out.println("IP : " + request.getRemoteAddr());
        System.out.println("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        System.out.println("ARGS : " + Arrays.toString(joinPoint.getArgs()));
*/
    }

    /**
     * 后置通知
     *
     * @param ret
     * @throws Throwable
     */
    @AfterReturning(returning = "ret", pointcut = "aopRestTemplete()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容

    }

    //后置异常通知
    @AfterThrowing("aopRestTemplete()")
    public void throwss(JoinPoint jp) {

    }

    //后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
    @After("aopRestTemplete()")
    public void after(JoinPoint jp) {

    }

    /**
     * 环绕通知
     *
     * @param pjp
     * @return
     */
    @Around("aopRestTemplete()")
    public Object arround(ProceedingJoinPoint pjp) {
        Object[] parames = pjp.getArgs(); //获取目标方法体参数
        //判断是开发环境还是生产环境
        boolean isDevMode = isDevMode();
        if (isDevMode) { //开发环境
            //查询本地是否有此端口号
            String url = parames[0].toString(); //TODO　判断空
            log.debug("url:{}", url);
            try {
                URL paseUrl = new URL(url);
                log.debug("host：{}", paseUrl.getHost());

                String serverHost = env.getProperty(paseUrl.getHost());
                if (!StringUtils.isNotEmpty(serverHost)) {
                    //TODO　未配置环境的情况处理
                    serverHost = "";
                }
                String[] ipAndPort = serverHost.split(":");
                if (ipAndPort != null && ipAndPort.length > 1) {
                    int port = Integer.parseInt(serverHost.split(":")[1]);
                    boolean flag = isLocalPortUsing(port);
                    if (flag) {
                        DnsCacheManipulator.setDnsCache(serverHost, "127.0.0.1");
                    } else {
                        DnsCacheManipulator.setDnsCache(serverHost, serverHost.split(":")[0]);
                    }
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            }
        }
        try {
            Object o = pjp.proceed(parames);
            return o;
        } catch (Throwable e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 获取当前运行环境为开发环境还是运行环境
     * 若指定为 dev,test,pre,prod
     */
    public boolean isDevMode() {
        String dev = System.getProperty("env");
        log.debug("环境为：{}", dev);
        if (StringUtils.equals(dev, "dev") || StringUtils.equals(dev, "test") || StringUtils.equals(dev, "pre") || StringUtils.equals(dev, "prod")) {
            return false;
        }
        return true;
    }

    /**
     * 测试本机端口是否被使用
     *
     * @param port
     * @return
     */
    public static boolean isLocalPortUsing(int port) {
        boolean flag = true;
        try {
            //如果该端口还在使用则返回true,否则返回false,127.0.0.1代表本机
            flag = isPortUsing("127.0.0.1", port);
        } catch (Exception e) {
        }
        return flag;
    }

    /***
     * 测试主机Host的port端口是否被使用
     * @param host
     * @param port
     * @throws UnknownHostException
     */
    public static boolean isPortUsing(String host, int port) throws UnknownHostException {
        boolean flag = false;
        InetAddress Address = InetAddress.getByName(host);
        try {
            Socket socket = new Socket(Address, port);  //建立一个Socket连接
            flag = true;
        } catch (IOException e) {

        }
        return flag;
    }
}
